#include <cstring>
#include <stdio.h>
#include <iostream>
#include <netinet/in.h>
#include <map>
#include <arpa/inet.h>
#include <queue>
#include <algorithm>

#include "netDevice.h"
#include "dataDevice.h"
#include "unp.h"
#include "CCycleBuffer.h"
#include "signal.h"
#include "config.h"
#include "network.h"

using namespace std;

static const int OPEN_MAX = 10;

////////////////////////////////////
//                                //
//      433M Net Device           //
//                                //
////////////////////////////////////

static const int onFlag = 0x01;
static const int offFlag = 0x00;
static const int dataFlag = 0x02;

static const int rDataLen = sendDataSize - 4;

static const int timeout = 1; //second

bool isTimeout = false;

states state = START;
sendStates sstate = IDLE;

void signal_alarm(int sig)
{
	Signal(SIGALRM, signal_alarm);
	isTimeout = true;
	return;
}

FTTMDevice::FTTMDevice()
{
	device = new serialDataDevice(serialName.c_str(), serialSpeed.c_str());
	sendBuffQ = new queue<sendBuff>;

	device->open();
	sendable = true;
	turnedON = true;
}

FTTMDevice::~FTTMDevice()
{
	delete device;
	delete sendBuffQ;
}

bool FTTMDevice::on()
{
	cout<<"433M device: ON"<<endl;
	char on[sendDataSize];
	on[0] = onFlag;

	turnONOK = false;
	turnONFAIL = false;
	sstate = IDLE;

	while(!sendBuffQ->empty())
		sendBuffQ->pop();
	sendable = true;
	sendBuff sendB;
	sendB.size = pack(on, sizeof(on), sendB.buff);
	sendBuffQ->push(sendB);

	while(!turnONOK && !turnONFAIL)
		sleep(1);

	if(turnONOK)
		return true;
	else
		return false;
}

bool FTTMDevice::off()
{
	cout<<"433M device: OFF"<<endl;
	char off[sendDataSize];
	off[0] = offFlag;

	turnOFFOK = false;
	turnOFFFAIL = false;
	sstate = IDLE;

	while(!sendBuffQ->empty())
		sendBuffQ->pop();
  sendable = true;
	sendBuff sendB;
	sendB.size = pack(off, sizeof(off), sendB.buff);
	sendBuffQ->push(sendB);

	while(!turnOFFOK && !turnOFFFAIL)
		sleep(1);

	if(turnOFFOK)
		return true;
	else
		return false;
}

int FTTMDevice::write(char* buff, int size)
{
	sendBuff sendB;
	int left = size - 2;
	char sbuff[sendDataSize];
	//bzero(sbuff, sizeof(sbuff));

	sbuff[0] = dataFlag;	//Send data, other type is onFlag or offFlag
	sbuff[1] = buff[0];
	sbuff[2] = buff[1];
	while(left > 0)
	{
		bzero(sbuff + 3, sizeof(sbuff) - 3);
		int len = rDataLen>left?left:rDataLen;
		sbuff[3] = (char)len;

		memcpy(sbuff+4,buff+size-left,len);
		left -= len;

		bzero(sendB.buff, sizeof(sendB.buff));
		sendB.size = pack(sbuff, sizeof(sbuff), sendB.buff);

		sendBuffQ->push(sendB);
		//cout<<"push"<<endl;
	}

	return 0;
}

void FTTMDevice::setup()
{
	Signal(SIGALRM, signal_alarm);
	start();
}

void FTTMDevice::run()
{
	tcpServer server;
	server.Listen(netDeviceListenPort, "127.0.0.1");
	int sock = server.getSocket();

	struct sockaddr_in clientAddr;
	socklen_t sockLen = sizeof(clientAddr);

	int csock;
	while(true)
	{
		csock = Accept(sock, (SA*)&clientAddr, &sockLen);
		char paddr[INET_ADDRSTRLEN];
		cout<<"433 Device: Receive connect from "<<inet_ntop(AF_INET, &clientAddr.sin_addr, paddr, INET_ADDRSTRLEN)<<":"<<ntohs(clientAddr.sin_port)<<endl;
		if(strcmp(paddr, "127.0.0.1") || sockLen != sizeof(struct sockaddr_in))
			cout<<"433 Device: Connect from other host, refused.."<<endl;
		else
			break;
	}

	struct pollfd fds[2];

	fds[0].fd = csock;
	fds[0].events = POLLIN;

	fds[1].fd = device->getFd();
	fds[1].events = POLLIN;

	char dbuff[1000], sdbuff[1000], sockbuff[300];
	int sdlen;
	bool mConvert = false;

	unsigned char len;
	int res, readlen;
	CCycleBuffer buffer(2000);

	sendBuff *p;
	bool toRead433M = false;

	while(true)
	{	
		//cout<<"3"<<endl;
		while(!toRead433M && !sendBuffQ->empty())
		{
			//cout<<"2"<<endl;
			switch(sstate)
			{
				case IDLE:
					//cout<<"IDLE"<<endl;
					cout<<"sendBuffQ.size: "<<sendBuffQ->size()<<endl;
					if(sendBuffQ->size() > 0)
						sstate = SEND;
					break;

				case SEND:
					//cout<<"SEND"<<endl;
					p = &sendBuffQ->front();

					//DBUG
					/*
					cout<<"--------------------"<<endl;
					cout<<"433M device: write "<<p->size<<" bytes to serial."<<endl;
					for(int i=0;i<p->size;i++)
						printf("%02hhx ", p->buff[i]);
					cout<<endl<<"++++++++++++++++++++"<<endl;
					*/
					//Send data and pop
					device->write(p->buff, p->size);
					toRead433M = true;
					//cout<<"alarm(5)"<<endl;
					alarm(5);
					isTimeout = false;	
					sendable = false;
					sstate = WAITACK;
					break;

				case WAITACK:
					//cout<<"WAITACK"<<endl;
					if(isTimeout)
					{	
						cout<<"433M ACK timeout"<<endl;
						sstate = SEND;
					}
					else if(sendable)
					{
						sstate = POP;
						alarm(300);
						isTimeout = false;	
						//cout<<"alarm(300)"<<endl;
					}
					toRead433M = true;
					break;

				case POP:
					//cout<<"POP"<<endl;
					sendBuffQ->pop();
					cout<<"433M device: Send buffer size "<<sendBuffQ->size()<<endl;
					sstate = IDLE;
					break;
			}//switch	
		}

		//cout<<"***+"<<endl;
		toRead433M = false;

		res = TEMP_FAILURE_RETRY(poll(fds, 2, timeout*1000));
		//res = Poll(fds, 2, -1);

		//cout<<"poll res: "<<res<<endl;

		if(fds[0].revents & POLLIN)	//read data from server
		{
			Readn(fds[0].fd, &len, 1);    

			cout<<"--------------------"<<endl;
			cout<<"433M device: Read "<<(int)len<<" bytes(ID<1>+type<1,'C'or'D'>+data) from 433M server."<<endl;
			readlen = Readn(fds[0].fd, sockbuff, len);
			cout<<"433M device: Data will be sendto node of ID "<<(int)(unsigned char)sockbuff[0]<<endl;
			cout<<"++++++++++++++++++++"<<endl;

			//Write data to 433M server
			write(sockbuff, readlen);
		}

		if(fds[1].revents & POLLIN)	//read from 433M device
		{
			//***************** Read from 433M device *******//
			int dlen = Read(fds[1].fd, dbuff, sizeof(dbuff));

			//DBUG
			/*
			cout<<"--------------------"<<endl;
			cout<<"433M device: Receive "<<dlen<<" bytes from serial"<<endl;
			for(int i = 0;i<dlen;++i)
				printf("%02hhx ", *(dbuff + i));
			cout<<endl;
			cout<<"++++++++++++++++++++"<<endl;
			*/
			//****************** Read from 433M device **********//

			//********** Convert 7d5e->7e 7d5d->7d *********//
			int i = 0;
			sdlen = 0;

			if(mConvert)
			{
				if('\x5e' == dbuff[0])
				{
					sdbuff[0] = '\x7e';						
					i = 1;
				}
				else if('\x5d' == dbuff[0])
				{
					sdbuff[0] = '\x7d';
					i = 1;				
				}
				else
				{
					sdbuff[0] = '\x7d';
					i = 0;
				}

				sdlen = 1;
			}

			for(; i < dlen - 1; ++i)
			{
				if(dbuff[i] == '\x7d' && dbuff[i+1] == '\x5e')
				{
					sdbuff[sdlen++] = '\x7e';
					i++;
				}
				else if(dbuff[i] == '\x7d' && dbuff[i+1] == '\x5d')
				{
					sdbuff[sdlen++] = '\x7d';
					i++;
				}
				else
					sdbuff[sdlen++] = dbuff[i];
			}

			if('\x7d' == dbuff[dlen-1])
				mConvert = true;
			else
			{
				sdbuff[sdlen++] = dbuff[dlen - 1];
				mConvert = false;
			}
			//********** Convert 7d5e->7e 7d5d->7d *********//

			//write data to buff
			buffer.Write(sdbuff, sdlen);

			bool running = true;
			char type;
			char data[33];
			while(running)
			{
				//cout<<"1"<<endl;
				switch(state)
				{
					case START:
						//cout<<"START"<<endl;
						if(!buffer.isEmpty())
						{
							buffer.Read(&type, 1);
							//cout<<type<<endl;
							if(type == '\x7e')
								state = START2;
						}
						else
							running = false;
						break;

					case START2:
						//cout<<"START2"<<endl;
						if(!buffer.isEmpty())
						{
							buffer.Read(&type, 1);
							//cout<<type<<endl;
							switch(type)
							{
								case '\x43':
									state = ACK6;
									break;
								case '\x45':
									state = LEN35;
									break;
								case '\x7e':
									state = START2;
									break;
								default:
									state = START;
							}
						}
						else
							running = false;
						break;

					case ACK6:
						cout<<"433M device: ACK6"<<endl;
						if(buffer.GetLength() >= 4)
						{
							buffer.Read(data, 4);
							state = START;
						}
						else
							running = false;	//长度不够
						break;

					case LEN35:
						//cout<<"LEN35"<<endl;
						if(buffer.GetLength() >= 33)
						{
							//cout<<">=33"<<endl;
							buffer.Read(data, 33);
							/*
							for(int i=0;i<33;i++)
								printf("%02hhx ", data[i]);
							cout<<endl;
							*/
							if(data[32] == '\x7e')
								switch(data[8])
								{
								  case '\x00':
										cout<<"433M device: Close device success."<<endl;
										state = START;
										turnOFFOK = true;
										sendable = true;
										break;
									case '\x01':
										cout<<"433M device: Close device fail."<<endl;
										turnOFFFAIL = true;
										state = START;
										break;
									case '\x02':
										cout<<"433M device: Open device success."<<endl;
										turnONOK = true;
										state = START;
										sendable = true;
										break;
									case '\x03':
										cout<<"433M device: Open device fail."<<endl;
										turnONFAIL = true;
										state = START;
										sendable = true;
										break;
									case '\x04':
										state = ACK35;
										break;
									case '\x05':
										cout<<"433M device: Send data fail."<<endl;
										state = START;
										sendable = true;
										break;
									case '\x06':
										state = DATA;
										break;
									default:
										state = START;
										break;
								}
							else
								state = START;
						}
						else
						{
							running = false;	//长度不够
							//cout<<"<33"<<endl;
						}
						break;
					
					case ACK35:
						cout<<"433M device: ACK35"<<endl;
						sendable = true;
						state = START;
						break;
						
					case DATA:
						cout<<"433M device: DATA"<<endl;
						
						data[8] = data[11];
						data[11] = data[10];
						data[10] = data[9];
						data[9] = data[8] + 2;

						//DBUG
						/*
						cout<<"--------------------"<<endl;
						for(int i = 0;i<data[9] + 1;++i)
							printf("%02hhx ", *(data + 9+ i));
						cout<<endl;
						cout<<"433M device: Send "<<data[9] + 1<<" bytes to 433M server."<<endl;
						cout<<"++++++++++++++++++++"<<endl;
						*/
						Send(fds[0].fd, data + 9, data[9] + 1, 0);
						state = START;
						break;
				}
			}
		}//if(fds[1].revents & POLLIN)
	}
}

unsigned short int FTTMDevice::GetCrc16(char* InStr, unsigned int len)
{
	unsigned short int crc = 0;
	//cout<<"sizeof crc "<<sizeof(crc)<<endl;
	for(unsigned int i = 0; i < len; i++)
	{
		crc = crc ^ InStr[i] << 8;
		for(int j = 0; j < 8; j++)
		{
			if((crc & 0x8000) != 0)
				crc = (((crc << 1) ^ 0x1021)) & 0xffff;
			else
				crc = (crc<<1) & 0xffff;
		}
	}

	return crc & 0xffff;
}

int FTTMDevice::litend(void)
{
	int i = 0;
	((char *)(&i))[0] = 1;

	return (i == 1);
}

int FTTMDevice::pack(char *buff, int size, char *sbuff)
{
	char sendBuff[100];
	int len = 0;

	//Add header
	memcpy(sendBuff, "\x44\x00\x00\xFF\xFF\x00\x00", 7);
	len += 7;

	//Add length
	sendBuff[len] = char(size);
	len += 1;

	//Add ???
	memcpy(sendBuff + len, "\x00\x89", 2);
	len += 2;

	//Add payload
	memcpy(sendBuff + len, buff, size);
	len += size;

	//caculate crc16
	unsigned short crc;
	crc = GetCrc16(sendBuff, len);

	//Add crc
	if(litend()) //little endian
	{
		sendBuff[len ] = ((char *)(&crc))[0];
		sendBuff[len + 1] = ((char *)(&crc))[1];
	}
	else        //big endian
	{
		sendBuff[len] = ((char *)(&crc))[1];
		sendBuff[len + 1] = ((char *)(&crc))[0];
	}
	len += 2;

	int c = 1;

	//Add start flag
	sbuff[0] = 0x7e;

	for(int i=0;i<len;i++)
	{
		if(sendBuff[i] == 0x7d)
		{
			sbuff[i + c] = 0x7d;
			sbuff[i + c + 1] = 0x5d;
			c++;
		}
		else if(sendBuff[i] == 0x7e)
		{
			sbuff[i + c] = 0x7d;
			sbuff[i + c + 1] = 0x5e;
			c++;
		}
		else
			sbuff[i + c] = sendBuff[i];
	}

	//Add end
	sbuff[len + c] = 0x7e;

	return len + c + 1;
}
